package com.edou.base.controller;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.json.simple.JSONArray;
import org.json.simple.JSONObject;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.edou.base.constant.SessionConstant;
import com.edou.base.page.PageResult;
import com.edou.base.util.DateUtil;
import com.edou.base.util.JacksonUtil;
import com.edou.base.util.ReflectionUtil;
import com.edou.base.util.UUIDUtil;

public class BaseController{

	private static final int BUFFER_SIZE = 2048000;
	
	protected Log logger = LogFactory.getLog(getClass());

	public static final String STATUS_PARAMETER_NAME = "status";// 操作状态参数名称
	public static final String MESSAGE_PARAMETER_NAME = "message";// 操作消息参数名称
	public static final String TOKEN_PARAMETER_NAME = "token";	//操作token参数名称
	public static final String JSONARRAY_PARAMETER_NAME = "data";
	public static final String ERROR_PAGE= "/WEB-INF/pages/base/error.jsp";
	
	
	// 操作状态（警告、错误、成功）
	public enum Status {
		warn, error, success,fail
	}
	
	/**
	 * 返回json数据
	 * @param status
	 * @param msg
	 * @return
	 */
	protected ModelAndView ajaxJSON(Status status){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		
		return view;
	}
	
	/**
	 * 返回json数据
	 * @param status
	 * @param msg
	 * @return
	 */
	protected ModelAndView ajaxJSON(Status status,String msg){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME,msg);
		return view;
	}
	
	/**
	 * 返回json数据
	 * @param status
	 * @param msg
	 * @return
	 */
	protected ModelAndView ajaxJSON(Status status,JSONObject root){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(JSONARRAY_PARAMETER_NAME,root);
		return view;
	}
	
	/**
	 * 返回json数据
	 * @param status
	 * @param msg
	 * @param needToken
	 * @return
	 */
	protected ModelAndView ajaxJSON(Status status,String msg,boolean needToken,HttpServletRequest request){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		
		if(needToken){
			String tokenVal = UUIDUtil.uuid();
			request.getSession().setAttribute(SessionConstant.TOKEN,tokenVal);
			data.put(TOKEN_PARAMETER_NAME, tokenVal);
		}
		
		return view;
	}
	
	protected ModelAndView ajaxJSON(Status status,String msg,boolean needToken,String tokenName,HttpServletRequest request){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		
		if(needToken){
			String tokenVal = UUIDUtil.uuid();
			request.getSession().setAttribute(tokenName,tokenVal);
			data.put(TOKEN_PARAMETER_NAME, tokenVal);
		}
		
		return view;
	}
	
	protected ModelAndView ajaxJSON(Status status,String msg,Map<String,String> resultData){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		
		if(null != resultData){
			for(Map.Entry<String, String> entry : resultData.entrySet()){
				data.put(entry.getKey(), entry.getValue());
			}
			resultData.clear();
			resultData = null;
		}
		return view;
	}
	
	protected ModelAndView ajaxJSON(Status status,String msg,Map<String,String> resultData,boolean needToken,HttpServletRequest request){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		
		if(null != resultData){
			for(Map.Entry<String, String> entry : resultData.entrySet()){
				data.put(entry.getKey(), entry.getValue());
			}
			resultData.clear();
			resultData = null;
		}
		
		if(needToken){
			String tokenVal = UUIDUtil.uuid();
			request.getSession().setAttribute(SessionConstant.TOKEN,tokenVal);
			data.put(TOKEN_PARAMETER_NAME, tokenVal);
		}
		
		return view;
	}
	
	protected ModelAndView ajaxJSON(Status status,String msg,Map<String,String> resultData,boolean needToken,String tokenName,HttpServletRequest request){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		
		if(null != resultData){
			for(Map.Entry<String, String> entry : resultData.entrySet()){
				data.put(entry.getKey(), entry.getValue());
			}
			resultData.clear();
			resultData = null;
		}
		
		if(needToken){
			String tokenVal = UUIDUtil.uuid();
			request.getSession().setAttribute(tokenName,tokenVal);
			data.put(TOKEN_PARAMETER_NAME, tokenVal);
		}
		
		return view;
	}
	
	protected ModelAndView ajaxJSON(Status status,String msg,JSONArray array){
		ModelAndView view = new ModelAndView("jsonView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		
		if(null != array){
			data.put(JSONARRAY_PARAMETER_NAME, array);
		}
		
		
		return view;
	}
	/**
	 * 向客户端输出json格式字符串
	 * 
	 * @param str
	 */
	protected void outJsonString(String str,HttpServletResponse response) {
		response.setContentType("text/json;charset=UTF-8");
		try {
			PrintWriter out = response.getWriter();
			out.write(str);
		} catch (Exception e) {
		}
	}
	
	
	
	protected ModelAndView ajaxHTML(Status status,String msg,Map<String,String> resultData){
		ModelAndView view = new ModelAndView("htmlView");
		Map<String,Object> data = view.getModel();
		data.put(STATUS_PARAMETER_NAME, status);
		data.put(MESSAGE_PARAMETER_NAME, msg);
		if(null != resultData){
			for(Map.Entry<String, String> entry : resultData.entrySet()){
				data.put(entry.getKey(), entry.getValue());
			}
			resultData.clear();
			resultData = null;
		}
		return view;
	}
	
	/**
	 * 输入分页数据
	 * @param root
	 * @param response
	 */
	@SuppressWarnings("unchecked")
	protected void ajaxPageResult(JSONObject root,HttpServletResponse response) {
		try{
			response.setContentType("text/json;charset=UTF-8");
			response.setDateHeader("Expires", 1L);
			response.addHeader("Pragma", "no-cache");
			response.setHeader("Cache-Control", "no-cache, no-store, max-age=0");
			root.put(STATUS_PARAMETER_NAME,Status.success);
			JacksonUtil.getMapper().writeValue(response.getWriter(), root);
		}catch(Exception ex){
			logger.error(ex.getMessage(),ex);
		}
	}
	
	/**
	 * 输入分页数据
	 * @param root
	 * @param response
	 */
	@SuppressWarnings("unchecked")
	protected void ajaxPageResult(JSONObject root,HttpServletResponse response,String dateFormat) {
		try{
			response.setContentType("text/json;charset=UTF-8");
			response.setDateHeader("Expires", 1L);
			response.addHeader("Pragma", "no-cache");
			response.setHeader("Cache-Control", "no-cache, no-store, max-age=0");
			root.put(STATUS_PARAMETER_NAME, Status.success);
			ObjectMapper mapper = JacksonUtil.getMapper();
			mapper.setDateFormat(new SimpleDateFormat(dateFormat));
			mapper.writeValue(response.getWriter(), root);
		}catch(Exception ex){
			logger.error(ex.getMessage(),ex);
		}
	}
	
	/**
	 * 获取网站地址
	 * @param request
	 * @return
	 */
	protected String getBaseUrl(HttpServletRequest request){
		String path = request.getContextPath();
		StringBuffer basePath = new StringBuffer();
		basePath.append(request.getScheme());
		basePath.append("://");
		basePath.append(request.getServerName());
		int port = request.getServerPort();
		if(port != 80){
			basePath.append(":").append(port);
		}
		basePath.append(path).append("/");
		return basePath.toString();
	}
		
	/**
	 * 获取IP地址
	 * @param request
	 * @return
	 */
	protected String getIpAddr(HttpServletRequest request){
		String ip = request.getHeader("X-Real-IP");
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getHeader("X-Forwarded-For");
		} else {
			return ip;
		}
		if (StringUtils.isBlank(ip) || "unknown".equalsIgnoreCase(ip)) {
			ip = request.getRemoteAddr();
		} else {
			int index = ip.indexOf(',');
			if (index != -1) {
				ip = ip.substring(0, index);
			}
		}
		return ip;
	}
	
	
	/**
	 * 存入cookie
	 * @param cookieName
	 * @param cookieValue
	 * @param request
	 * @param response
	 */
	protected void putValueToCookie(String cookieName,String cookieValue,Integer expiry,HttpServletResponse response){
		//存入cookie中
		Cookie cookie = new Cookie(cookieName,cookieValue);
		cookie.setPath("/");
		if(null != expiry){
			cookie.setMaxAge(expiry);
		}
		response.addCookie(cookie);
	}

	/**
	 * 获取存在cookie中的值
	 * @param request
	 * @return
	 */
	protected String getValueFromCookie(String cookieKeyName,HttpServletRequest request){
		String cookieValue = null;
		Cookie cookies[] = request.getCookies();
		if (null != cookies) {
			for (Cookie cookie : cookies) {
				if (cookieKeyName.equals(cookie.getName())) {
					cookieValue = cookie.getValue();
					break;
				}
			}
		}
		return cookieValue;
	}
	
	/**
	 * 从cookie中删除当前会员
	 * @param request
	 * @param response
	 * @return 存在cookie中的key值
	 */
	protected String removeValueFromCookie(String removeCookieName,HttpServletRequest request,HttpServletResponse response){
		String cookieValue = null;
		Cookie cookies[] = request.getCookies();
		if (null != cookies) {
			for (Cookie cookie : cookies) {
				if (removeCookieName.equals(cookie.getName())) {
					cookieValue = cookie.getValue();
					Cookie deleteCookie = new Cookie(cookie.getName(),null);
					deleteCookie.setPath("/");
					deleteCookie.setMaxAge(0);	//立即删除
					response.addCookie(deleteCookie);
					
					break;
				}
			}
		}
		return cookieValue;
	}
	
	/**
	 * 生成JSONObject对象
	 * @param itemList
	 */
	@SuppressWarnings("unchecked")
	public static JSONObject toJsonResultList(List<?> itemList,String[] includeProperties) {
		JSONObject root = new JSONObject();
		JSONArray array = new JSONArray();
		root.put("resultList", array);
		
		for(int i=0;i<itemList.size();i++){
			JSONObject json = new JSONObject();
			Object obj = itemList.get(i);
			for(String includeProperty : includeProperties){
				json.put(includeProperty,ReflectionUtil.invokeGetterMethod(obj, includeProperty));
			}
			array.add(json);
		}
		return root;
	}
	
	/**
	 * 分页json构建
	 * 
	 * @param page
	 *            分页信息
	 * @param resultList
	 *            结果集json数组
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static JSONObject toPageJson(@SuppressWarnings("rawtypes") PageResult pageResult,String[] includeProperties) {
		JSONObject jsonObject = new JSONObject();
		try {
			jsonObject.put("pageResult.currentPage", pageResult.getCurrentPage());
			jsonObject.put("pageResult.rows", pageResult.getRows());
			jsonObject.put("pageResult.allPages", pageResult.getAllPages());
			
			JSONArray array = new JSONArray();
			jsonObject.put("resultList", array);
			
			for(int i=0;i<pageResult.getResult().size();i++){
				JSONObject json = new JSONObject();
				Object obj = pageResult.getResult().get(i);
				for(String includeProperty : includeProperties){
					json.put(includeProperty,ReflectionUtil.invokeGetterMethod(obj, includeProperty));
				}
				array.add(json);
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}
		return jsonObject;
	}

	/**
	 * 获取当前访问的url路径，带参数
	 * 
	 * @param request
	 * @return
	 * @throws UnsupportedEncodingException
	 */
	@SuppressWarnings("unchecked")
	public static String getPrevUrl(HttpServletRequest request) throws UnsupportedEncodingException {
		StringBuffer prevUrl = request.getRequestURL();
		Map<String, String[]> map = request.getParameterMap();
		Iterator<String> iter = map.keySet().iterator();
		int i = 0;
		while (iter.hasNext()) {
			String key = iter.next();
			String[] value = map.get(key);
			if (i == 0) {
				prevUrl.append("?");
			} else {
				prevUrl.append("&");
			}
			for (int j = 0; j < value.length; j++) {
				prevUrl.append(key).append("=").append(value[j]);
				if (j != value.length - 1) {
					prevUrl.append("&");
				}
			}

			i++;
		}

		return prevUrl.toString();
	}
	
	
	// 获取Cookie
	protected String getCookie(String name,HttpServletRequest request,HttpServletResponse response) {
		Cookie cookies[] = request.getCookies();
		if (cookies != null) {
			for (Cookie cookie : cookies) {
				if (name.equals(cookie.getName())) {
					return cookie.getValue();
				}
			}
		}
		return null;
	}
	
	// 设置Cookie
	protected void setCookie(String name,String value,HttpServletRequest request,HttpServletResponse response) {
		Cookie cookie = new Cookie(name, value);
		cookie.setPath(request.getContextPath() + "/");
		response.addCookie(cookie);
	}
	
	// 设置Cookie
	protected void setCookie(String name, String value,Integer maxAge, HttpServletRequest request, HttpServletResponse response) {
		Cookie cookie = new Cookie(name, value);
		if (maxAge != null) {
			cookie.setMaxAge(maxAge);
		}
		cookie.setPath(request.getContextPath() + "/");
		response.addCookie(cookie);
	}

	// 移除Cookie
	protected void removeCookie(String name,HttpServletRequest request,HttpServletResponse response) {
		Cookie cookie = new Cookie(name, null);
		cookie.setMaxAge(0);
		cookie.setPath(request.getContextPath() + "/");
		response.addCookie(cookie);
	}
	
	/**
	 * 获得绝对路径
	 * 
	 * @param path
	 * @return
	 */
	public static String getRealPath(String path,HttpServletRequest request) {
		return request.getSession().getServletContext().getRealPath(path);
	}
	
	/**
	 * 上传文件
	 * @param uploadFile
	 * @param filePath
	 * @param request
	 * @return
	 */
	protected String doUploadFile(MultipartFile uploadFile,String filePath,HttpServletRequest request) {
		//1.文件存储在临时目录上
		String fileName = uploadFile.getOriginalFilename();
	    //获取上传文件类型的扩展名,先得到.的位置，再截取从.的下一个位置到文件的最后，最后得到扩展名  
        String fileExt = fileName.substring(fileName.lastIndexOf("."),fileName.length()).toLowerCase();  
		String tmpDir = System.getProperty("java.io.tmpdir");
		String tmpFilePath = tmpDir + File.separator + uuid() + fileExt;
		File tmpFile = new File(tmpFilePath);
		String returnFilePath  =null;
		try{
			uploadFile.transferTo(tmpFile);
			String fileType = "";
			int point = fileName.lastIndexOf(".");
			if (point != -1) {
				fileType = fileName.substring(point);
			}
			if (tmpFile.length() <= 76939047) {
				String time = String.valueOf(new Date().getTime());
				String saveFileName = time + (int) (Math.random() * 100) + fileType;
				String realPath = this.getRealyPath(filePath,request);
				Date now = new Date();
				String subDir = DateUtil.formatDate(now, "yyyy-MM-dd");
				realPath = realPath + File.separator + subDir;
				File dir = new File(realPath);
				boolean createSuccess = false;
				if (!dir.exists()) {
					createSuccess = dir.mkdirs();
				} else {
					createSuccess = true;
				}
				if (createSuccess) {
					String destPath = realPath + File.separator + saveFileName;
					File destFile = new File(destPath);
					this.upload(tmpFile, destFile);
				} else {
					saveFileName = null;
				}
				returnFilePath= filePath + "/" + subDir + "/" + saveFileName;
			} else {
				returnFilePath = null;
			}
		}catch(Exception ex){
			String msg = "上传临时文件失败:"+ex.getMessage();
			logger.error(msg,ex);
		}finally{
			FileUtils.deleteQuietly(tmpFile);
		}
		return returnFilePath;
	}
	/**
	 * 上传文件
	 * 
	 * @param src
	 *            源文件
	 * @param dst
	 *            目标文件
	 */
	protected void upload(File src, File dst) {
		try {
			InputStream in = null;
			OutputStream out = null;
			try {
				in = new BufferedInputStream(new FileInputStream(src),
						BUFFER_SIZE);
				out = new BufferedOutputStream(new FileOutputStream(dst),
						BUFFER_SIZE);
				byte[] buffer = new byte[BUFFER_SIZE];
				int length = 0;
				while ((length = in.read(buffer)) != -1) {
					out.write(buffer, 0, length);
				}
				out.flush();
			} finally {
				IOUtils.closeQuietly(in);
				IOUtils.closeQuietly(out);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * 输出到客户端
	 * @param fileName
	 * @param localFile
	 */
	protected void writeToClient(String fileName,String filePath,HttpServletRequest request,HttpServletResponse response) {
		File downloadFile = null;
		try {
			String agent = request.getHeader("User-Agent");
			logger.info("download file,agent:" + agent);
			if (agent.toUpperCase().indexOf("IE") > 0 || agent.indexOf("Trident") != -1) {
				//IE
				fileName = URLEncoder.encode(fileName, "UTF-8");
			}else{
				//other
				fileName = new String(fileName.getBytes("UTF-8"), "ISO-8859-1");
			}
			
			String contentType = "application/x-msdownload";	//默认类型
			if(agent.indexOf("Safari") != -1){
				//苹果mac系统上，safari浏览器对默认的contentType支持不好，换一下
				contentType = "applicatoin/octet-stream";
			}
			contentType += ";charset=UTF-8";
			
			//设置响应头
			response.reset();
			response.setContentType(contentType);
			response.setCharacterEncoding("UTF-8");
			response.addHeader("Content-Disposition", "attachment; filename=\"" + fileName + "\"");
			
			// path是指欲下载的文件的路径。
			downloadFile = new File(filePath);
			int fileLength = (int) downloadFile.length();
			response.setContentLength(fileLength);
			/* 创建输入流 */
			InputStream inStream = new FileInputStream(downloadFile);
			byte[] buf = new byte[4096];
			/* 创建输出流 */
			ServletOutputStream servletOS = response.getOutputStream();
			int readLength;
			while (((readLength = inStream.read(buf)) != -1)) {
				servletOS.write(buf, 0, readLength);
			}
			
			inStream.close();
			servletOS.flush();
			servletOS.close();
		} catch (Exception e) {
			logger.error("",e);
		}
	}

	/**
	 * 获取物理路径
	 * 
	 * @param path
	 * @return 返回路径
	 */
	protected String getRealyPath(String path,HttpServletRequest request ) {
		if (path == null) {
			return "";
		}
		return request.getSession().getServletContext().getRealPath(path).replace("\\", "/");
	}
	/**
	 * 生成uuid 去除"-"
	 * @return
	 */
	 protected String uuid(){
       String uuid=java.util.UUID.randomUUID().toString().toLowerCase().replaceAll("-", "");
       return uuid;
	 }
	 
	 //这个类初始化的时候会首先调用init方法
     @InitBinder  //类初始化是调用的方法注解
     public void initBinder(WebDataBinder binder) {  
        //给这个controller配置接收list的长度100000，仅在这个controller有效
        binder.setAutoGrowCollectionLimit(100000); 
     }
}
